/**
 * 开发者   : Marco
 * 创建时间 : 2017年5月19日, 下午5:45
 */

#include "string.hpp"

#include <string.h>
#include <stdlib.h>
#include <ostream>

#ifndef MARCO_NO_STRING

#define	    LONG_MAX_SIZE   (size_t)0x3fffffff // 长串最大长度
#define	    SMALL_MAX_SIZE  (size_t)(sizeof(char*)+sizeof(int)+sizeof(unsigned short))  // 短串最大长度
#define	    SMALL_PTR	    (char*)&ptr_    // 短串时的取字符串首地址

#define	    LONG_FLAG	    15	// 长串标志位
#define	    EMPTY_FLAG	    0	// 空串标志位
#define	    SET_LONG_FLAG   (flg_ = LONG_FLAG) // 设置长串标志
#define	    SET_EMPTY_FLAG  (flg_ = EMPTY_FLAG) // 设置空串标志

#define	    IS_EMPTY	    (flg_ == 0)  // 是否空串
#define	    IS_LONG	    (flg_ == LONG_FLAG)	// 是否长串

#define	    MALLOC	    malloc
#define	    REALLOC	    realloc
#define	    FREE	    free
#define	    MEMCPY	    memcpy
#define	    MEMMOVE	    memmove

MARCOPP_NAMESPACE_BEGIN

// 构造与析构
string::string(void) MARCOPP_NOEXCEPT : flg_(EMPTY_FLAG) { }
string::string(const char* str) MARCOPP_NOEXCEPT { 
    if (!str) { SET_EMPTY_FLAG; } // 先判断空指针, 防止strlen崩溃
    else { set(str, strlen(str)); }
} 
string::string(const char* str, size_t len) MARCOPP_NOEXCEPT { set(str, len); }
string::string(const string& orig) MARCOPP_NOEXCEPT { 
    /* out_debug("copy construct, dst:%s, size:%lu.\n", orig.data(), orig.size()); */ 
    set(orig.data(), orig.size()); 
}
string::string(const std::string& orig) MARCOPP_NOEXCEPT { set(orig.data(), orig.size()); }
string::string(size_t n, char ch) MARCOPP_NOEXCEPT {
    if (n == 0) { SET_EMPTY_FLAG; return; } // 空串
    
    char* p;
    if (n > SMALL_MAX_SIZE) { // 长串
	capacity_ = len_ = n;
	p = ptr_ = (char*)MALLOC(n+1);
	SET_LONG_FLAG;
    } else { // 短串
	p = SMALL_PTR;
	flg_ = n;
    }
    
    for (size_t i = 0; i < n; ++i)
	p[i] = ch;
    p[n] = 0;
}
#if (__cplusplus >= 201103L)
string::string(string&& orig) MARCOPP_NOEXCEPT { // 移动构造
//    out_debug("move construct, dst:%s, size:%lu.\n", orig.data(), orig.size());
    this->fill_ = orig.fill_;
    this->ptr_ = orig.ptr_;
    orig.ptr_ = nullptr; // 移动后对方指针必须置为空
    orig.fill_ = 0; // 置为空串, 0长度, 析构时不会检查为长串, 省得调用free(NULL)
}
#endif

string::~string(void) {
    if (IS_LONG) { /* out_debug("Destroy, long string(%s), len:%lu, free it.\n", data(), size()); */ FREE(ptr_); }
//    else out_debug("Destroy, smart string(%s), len:%lu.\n", data(), size());
}

// 赋值运算
string& string::operator=(const string& orig) MARCOPP_NOEXCEPT { 
// out_debug("copy operator=, dst:%s, len:%lu.\n", orig.data(), orig.size());
    return assign(orig.data(), orig.size()); 
}
string& string::operator=(const std::string& orig) MARCOPP_NOEXCEPT { return assign(orig.data(), orig.size()); }
string& string::operator=(const char* str) MARCOPP_NOEXCEPT { return assign(str, str ? strlen(str) : 0); }
string& string::operator=(const char ch) MARCOPP_NOEXCEPT { return assign(&ch, 1); }

// 长度相关
size_t string::size(void) const MARCOPP_NOEXCEPT { return (IS_LONG ? len_ : flg_); }
size_t string::length(void) const MARCOPP_NOEXCEPT { return (IS_LONG ? len_ : flg_); }
size_t string::max_size() const MARCOPP_NOEXCEPT { return LONG_MAX_SIZE; }
size_t string::capacity(void) const MARCOPP_NOEXCEPT { return (IS_LONG ? capacity_ : SMALL_MAX_SIZE); }
void string::reserve(size_t n) {
    if (n >= LONG_MAX_SIZE)
	n = LONG_MAX_SIZE;
    
    if (IS_LONG) { // 当前长串时
	if (n > len_) { // 比当前实际长度大
	    if (capacity_ != n) { // 跟之前预留不相同才重新申请, 避免申请一样大小
		capacity_ = n;
		ptr_ = (char*)REALLOC(ptr_, capacity_+1);
	    }
	} else { // 小于等于当前长度, 表示不预留任何多余空间
	    if (len_ != capacity_) { // 当不相同时才收缩空间
		capacity_ = len_;
		ptr_ = (char*)REALLOC(ptr_, capacity_+1);
	    }
	}

    // 当前短串或空, 只有预设值超过短串最大长度, 才提前申请空间并转化为长串模式
    } else if (n > SMALL_MAX_SIZE) { 
	char* p = (char*)MALLOC(n+1); // 申请内存, 不能直接ptr_指过去, ptr_里面可能有短串的内容
	if (IS_EMPTY) { // 之前空串
	    len_ = 0;
	    *p = 0; // 置0, 防止data,c_str取到垃圾内容
	} else { // 当前短串, 需要拷贝之前内容
	    MEMCPY(p, SMALL_PTR, flg_); // 拷贝现有内容
	    p[flg_] = 0; // 结束符
	    len_ = flg_; // 换变量存储之前长度
	}
	capacity_ = n;
	ptr_ = p; // 指向堆地址
	SET_LONG_FLAG; // 置为长串模式
    }
    // else, 当前短串或空, 但预设值还是小于14, 忽略不处理
}

void string::clear(void) MARCOPP_NOEXCEPT { // 清空
    if (IS_LONG) 
	FREE(ptr_);
    SET_EMPTY_FLAG; // 置为空串
}

bool string::empty(void) const MARCOPP_NOEXCEPT { return IS_EMPTY; } // 是否为空

char string::at(size_t pos) const throw(int) {
    if (pos >= size())
	throw(MARCO_STRING_OUT_OF_RANGE);
    return data()[pos];
}

string& string::append(const string& str, size_t pos, size_t n) throw(int) {
    size_t str_len = str.size();
    if (pos > str_len)
	throw(MARCO_STRING_OUT_OF_RANGE);
    size_t available = str_len - pos;
    return append(str.data()+pos, available > n ? n : available);
}
string& string::append(const std::string& str) throw(int) { return append(str.data(), str.size()); }
string& string::append(const std::string& str, size_t pos, size_t n) throw(int) {
    size_t str_len = str.size();
    if (pos > str_len)
	throw(MARCO_STRING_OUT_OF_RANGE);
    size_t available = str_len - pos; // 实际剩余字节数
    return append(str.data()+pos, available > n ? n : available); // 取较小者
}

string& string::append(const char* str) throw(int) { return str ? append(str, strlen(str)) : *this; } // 不带长度的C字符串
string& string::append(size_t n, char ch) throw(int) { // 添加n个相同字符
    if (!n) return *this;
    char buf[n];
    for (size_t i = 0; i < n; ++i)
	buf[i] = ch;
    return append(buf, n);
}
// append最终实现
string& string::append(const char* str, size_t len) throw(int) {
    if (IS_EMPTY) { // 当前空串
	set(str, len); // 直接设置
	return *this;
    }
    
    if (!str || !len) // 新长度为空, 忽略不处理
	return *this;
    
    // 非空串, 长度相加
    size_t old_len = length();
    size_t total_len = len + old_len;
    
    if (total_len > LONG_MAX_SIZE) { // 不能超过总长度
	throw(MARCO_STRING_TOO_LONG);
    }
    
    if (IS_LONG) { // 当前长串, 再加肯定还是长串
	if (total_len > capacity_) { // 超过预留大小
	    capacity_ *= 2; // 提高2倍
	    if (total_len > capacity_) // 依然不够, 则使用当前长度, 不预留 
		capacity_ = total_len;
	    ptr_ = (char*)REALLOC(ptr_, capacity_+1);
	}
	
	len_ = total_len; // 更新长度
	MEMCPY(ptr_+old_len, str, len); // 追加
	ptr_[total_len] = 0;
	
    } else { // 当前短串
	if (total_len > SMALL_MAX_SIZE) { // 新长度为长串
	    // 首次申请的内存为刚好大小, 并不额外预留
	    char* p = (char*)MALLOC(total_len+1); // 临时变量, 不能将ptr_覆盖掉, 其中还有之前的字符信息
	    MEMCPY(p, SMALL_PTR, old_len); // 原数据
	    MEMCPY(p+old_len, str, len); // 新数据
	    p[total_len] = 0;
	    ptr_ = p;
	    capacity_ = len_ = total_len; // 长度
	    SET_LONG_FLAG; // 长串标志
	    
	} else { // 依然短串
	    flg_ = total_len; // 更新长度
	    char* p = SMALL_PTR;
	    MEMCPY(p+old_len, str, len); // 追加
	    p[total_len] = 0; // 新的结束符
	}
    }
    
    return *this;
}

// insert插入
string& string::insert(size_t pos, const string& ins_str, size_t ins_pos, size_t ins_len) throw(int) {
    size_t length = ins_str.size();
    if (ins_pos > length) throw(MARCO_STRING_OUT_OF_RANGE);
    if (length == ins_pos) return *this; // 拷贝起始位置等于长度, 是结束符, 忽略
    size_t tmp = length - ins_pos; // 子串实际剩余的字符个数, 不可能为0
    length = tmp > ins_len ? ins_len : tmp; // 最终拷贝的字符个数, 取较小的值, 不能越界
    return insert(pos, ins_str.data()+ins_pos, length); // 使用原始C字符串偏移的方式
}
string& string::insert(size_t pos, const std::string& ins_str) throw(int) { return insert(pos, ins_str.data(), ins_str.size()); }
string& string::insert(size_t pos, const std::string& ins_str, size_t ins_pos, size_t ins_len) throw(int) { // 同上
    size_t length = ins_str.length();
    if (ins_pos > length) 
	throw(MARCO_STRING_OUT_OF_RANGE);
    if (length == ins_pos)
	return *this;
    size_t tmp = length - ins_pos;
    length = tmp > ins_len ? ins_len : tmp;
    return insert(pos, ins_str.data()+ins_pos, length); 
}
string& string::insert(size_t pos, const char* str) throw(int) { return insert(pos, str, str ? strlen(str) : 0); }
string& string::insert(size_t pos, const char* ins_str, size_t ins_len) throw(int) {
    if (!ins_str || !ins_len) // 零长度或空指针忽略
	return *this;
    
    size_t old_len = length(); // 原来的长度
    size_t total_len = ins_len + old_len; // 总长度
    
    if (pos > old_len) // 插入位置超出长度
	throw(MARCO_STRING_OUT_OF_RANGE);
    if (total_len > LONG_MAX_SIZE)  // 不能超过总长度
	throw(MARCO_STRING_TOO_LONG);
    
    size_t after_len = old_len - pos; // 原串从插入的位置后面还有多少字节
    
    if (IS_LONG) { // 当前长串, 再加肯定还是长串
	if (total_len > capacity_) { // 超过预留大小
	    capacity_ *= 2; // 提高2倍
	    if (total_len > capacity_) // 依然不够, 则使用当前长度, 不预留 
		capacity_ = total_len;
	    ptr_ = (char*)REALLOC(ptr_, capacity_+1);
	}
	
	if (after_len) // 原来的内容向后移
	    MEMMOVE(ptr_+pos+ins_len, ptr_+pos, after_len); 
	
	MEMCPY(ptr_+pos, ins_str, ins_len); // 拷贝插入的串
	ptr_[total_len] = 0;
	len_ = total_len; // 更新长度
	
    } else { // 当前短串
	if (total_len > SMALL_MAX_SIZE) { // 新长度为长串
	    // 首次申请的内存为刚好大小, 并不额外预留
	    char* p = (char*)MALLOC(total_len+1); // 临时变量, 不能将ptr_覆盖掉, 其中还有之前的字符信息
	    size_t before_len = old_len-after_len;
	    if (before_len) // 原数据前面的内容拷贝
		MEMCPY(p, SMALL_PTR, before_len); 
	    if (after_len) // 原数据后面的内容拷贝到最后
		MEMCPY(p+pos+ins_len, SMALL_PTR+pos, after_len); 
	    MEMCPY(p+pos, ins_str, ins_len); // 拷贝插入的串到中间
	    p[total_len] = 0;
	    ptr_ = p;
	    capacity_ = len_ = total_len; // 长度
	    SET_LONG_FLAG; // 长串标志
	    
	} else { // 依然短串
	    flg_ = total_len; // 更新长度
	    char* p = SMALL_PTR;
	    if (after_len) // 原来后面的内容向后移
		MEMMOVE(p+pos+ins_len, p+pos, after_len); 
	    MEMCPY(p+pos, ins_str, ins_len); // 追加
	    p[total_len] = 0; // 新的结束符
	}
    }
    
    return *this;
}

size_t string::copy(char* buf, size_t count, size_t pos) const MARCOPP_NOEXCEPT {
    size_t cur_size = size();
    
    if (cur_size < pos) return 0; // 越界, 空串时必定越界
    
    size_t copy_count = cur_size > count ? count : cur_size; // 要拷贝的字符个数, 取较小的
    char* p = (IS_LONG ? ptr_ : SMALL_PTR); // 根据长串或短串取首地址
    
    for (size_t i = 0; i < copy_count; ++i) {
	buf[i] = p[pos+i];
    }
    
    buf[copy_count] = 0;
    return copy_count;
}

void string::swap(string& str) MARCOPP_NOEXCEPT {
    char* tmp_ptr = str.ptr_;
    str.ptr_ = ptr_;
    ptr_ = tmp_ptr;

    u64 tmp_value = str.fill_;
    str.fill_ = fill_;
    fill_ = tmp_value;
}

const char* string::data(void) const MARCOPP_NOEXCEPT { return IS_EMPTY ? "" : (IS_LONG ? ptr_ : SMALL_PTR); }
const char* string::c_str(void) const MARCOPP_NOEXCEPT { return IS_EMPTY ? "" : (IS_LONG ? ptr_ : SMALL_PTR); }

int string::compare(const char* str) const MARCOPP_NOEXCEPT {
    if (IS_EMPTY) { return (str && *str) ? -1 : 0; }
    if (!str || *str == 0) { return 1; }
    return strcmp(data(), str);
}
int string::compare(const std::string& str) const MARCOPP_NOEXCEPT { return compare(str.data()); }
int string::compare(const string& str) const MARCOPP_NOEXCEPT { return compare(str.data()); }


// ----------------- 私有
 
/**
 * 设置新值
 * @param str 字符串
 * @param len 长度
 */
void string::set(const char* str, size_t len) {
    if (!str || !len) {
	SET_EMPTY_FLAG;
	return;
    }
    
    char* p;
    if (len > SMALL_MAX_SIZE) { // 长串, 需要申请空间
	this->len_ = this->capacity_ = len;
	p = this->ptr_ = (char*)MALLOC(len+1);
	SET_LONG_FLAG; // 长串标志位
    } else { // 小字符串
	p = SMALL_PTR;
	flg_ = len; // 长度
    }
    
    MEMCPY(p, str, len);
    p[len] = 0; // 手动置结束符
}

string& string::assign(const char* str, size_t len) {
    if (!IS_LONG) { // 之前非长串
	set(str, len); 
	
    } else if (len <= SMALL_MAX_SIZE) { // 之前是长串, 但新的是短串
	FREE(ptr_); // 释放原有堆内存
	set(str, len); 
	
    } else { // 新长度还是长串
	if (len > this->capacity_) { // 新长度比预留空间大, 需要重新分配内存
	    capacity_ = len;
	    FREE(ptr_);
	    ptr_ = (char*)MALLOC(len+1);
	} 
	
	len_ = len;
	MEMCPY(ptr_, str, len);
	ptr_[len] = 0;
    } 
    
    return *this;
}

// operator+
#if __cplusplus >= 201103L
string operator+(string&& left, const string& right) { return std::move(left.append(right)); }
string operator+(const string& left, string&& right) { return std::move(right.insert(0, left)); }
string operator+(string&& left, string&& right) { return std::move(left.append(right)); }

string operator+(const std::string& left, string&& right) { return std::move(right.insert(0, left)); }
string operator+(string&& left, std::string right) { return std::move(left.append(right)); }

string operator+(string&& left, const char* right) { return std::move(left.append(right)); }
string operator+(const char* left, string&& right) { return std::move(right.insert(0, left)); }

string operator+(string&& left, char right) { return std::move(left.append(&right, 1)); }
string operator+(char left, string&& right) { return std::move(right.insert(0, &left, 1)); }
#endif

std::ostream& operator<<(std::ostream& output, const string& str) {
    output << str.data();
    return output;
}


MARCOPP_NAMESPACE_END
#endif // MARCO_NO_STRING